

/******************************************************************
Copyright © PsuCtl 2017~2023. All rights reserved.
* @projectName   PsuCtl
* @author        Raiiwhen
* @email         masterraii@icloud.com
* @origin        ESP udp_multicase_example
*******************************************************************/

#include <string.h>
#include <sys/param.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_netif.h"

#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include <lwip/netdb.h>
#include "esp_mac.h"

static const char *TAG = "mcast-ipv4";
static char g_beaconInfo[128] = "aliveReport: initing";
static SemaphoreHandle_t g_beaconLiveSem;
static int g_isInit = 0;

int BeaconAliveReport(void *pvParameters)
{
   int opt_val = 1;
   esp_err_t err = ESP_FAIL;
   struct sockaddr_in from_addr = {0};
   socklen_t from_addr_len = sizeof(struct sockaddr_in);
   char udp_recv_buf[64 + 1] = {0};

   // 创建 IPv4 UDP 套接字
   int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
   if (sockfd == -1) {
      ESP_LOGE(TAG, "Create UDP socket fail");
      return err;
   }

    // 设置广播接收地址和端口
   struct sockaddr_in server_addr = {
      .sin_family      = AF_INET,
      .sin_port        = htons(4444),
      .sin_addr.s_addr = htonl(INADDR_ANY),
   };

   int ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
   if (ret < 0) {
      ESP_LOGE(TAG, "Bind socket fail");
      goto exit;
   }

   // 设置 SO_BROADCAST 套接字选项， 使能该套接字支持广播发送
    struct timeval tv = {
        .tv_sec = 0,
        .tv_usec = 500 * 1000,
    };
   ret = setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &opt_val, sizeof(int));
   ret = setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
   if (ret < 0) {
      ESP_LOGE(TAG, "Set SO_BROADCAST option fail");
      goto exit;
   }

   // 设置广播发送地址和端口
   struct sockaddr_in dest_addr = {
      .sin_family      = AF_INET,
      .sin_port        = htons(3333),
      .sin_addr.s_addr = htonl(INADDR_BROADCAST),
   };
   g_beaconLiveSem = xSemaphoreCreateMutex();
   // 调用 sendto 接口发送广播数据
   while (1) {
        xSemaphoreTake(g_beaconLiveSem, 0);
        ret = sendto(sockfd, g_beaconInfo, strlen(g_beaconInfo), 0, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr));
        xSemaphoreGive(g_beaconLiveSem);
        g_isInit = 1;
        if (ret < 0) {
            ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);
        } else {
            ret = recvfrom(sockfd, udp_recv_buf, sizeof(udp_recv_buf) - 1, 0, (struct sockaddr *)&from_addr, (socklen_t *)&from_addr_len);
            if (ret > 0) {
                ESP_LOGI(TAG, "Receive udp unicast from %s:%d, data is %s", inet_ntoa(((struct sockaddr_in *)&from_addr)->sin_addr), ntohs(((struct sockaddr_in *)&from_addr)->sin_port), udp_recv_buf);
                err = ESP_OK;
            }
        }
        vTaskDelay(100);
    }

exit:
   close(sockfd);
   return err;
}

void BeaconAliveInfoConfig(const char* devType, const char* ip, int rssi)
{
    if (!g_isInit) {
        return;
    }
    uint8_t mac[6] = {0};
    esp_efuse_mac_get_default(mac);
    xSemaphoreTake(g_beaconLiveSem, 0);
    sprintf(g_beaconInfo, "aliveReport: type=%s, ip=%s, rssi=%d, mac=%02x:%02x:%02x:%02x:%02x:%02x",
            devType, ip, rssi, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
    xSemaphoreGive(g_beaconLiveSem);
}